#ifdef WIN32
#	include "../../socket/internal/IocpService.h"
#elif defined(LINUX)
#	include "../../socket/internal/EpollService.h"
#	include "../../socket/SockTools.h"
#endif
#include "IpcServer.h"
#include "IpcSocket.h"
#include "../../socket/internal/SockData.h"
#include "../../socket/SockException.h"
#include "../../socket/Timer.h"
#include <assert.h>

DEF_BEG_LIBTOOLS

CIpcServer::CIpcServer(bool isWriteLog):CIpcBase(isWriteLog)
{
#ifdef WIN32
	_service.Reset(new CIocpService(&CIpcServer::IoCompleteFunc));
#elif defined(LINUX)
	_service.Reset(new CEpollService(&CIpcServer::IoCompleteFunc));
#endif
	_service->SetWriteLog(isWriteLog);
}

CIpcServer::~CIpcServer()
{
#ifdef LINUX
	if(_svrSock.Get() != NullPtr) unlink(_svrSock->GetAddr().c_str());
#endif
}

CSockError CIpcServer::Init(const char* name)
{
	CSockError ec;
	_svrSock = new CIpcSocket(this);
	_svrSock->SetAddr(name);
#ifdef WIN32
	_svrSock->SetProtocol(SOCKPROTOCOL::IPC_CREATE);
	_svrSock->SetDomain(SOCKFAMILY::IPC);
	_svrSock->SetSockType(SOCKTYPE::STREAM);
	_svrSock->GetServiceBuffer()->isBindService = TRUE;
#elif defined(LINUX)
	ec = dynamic_cast<CSocket*>(_svrSock.Get())->Socket(SOCKFAMILY::IPC, SOCKTYPE::STREAM, SOCKPROTOCOL::IPC_CREATE);
	if (!ec)
	{
		ec = Bind(*_svrSock);
		if (!ec)
		{
			ec = Listen(*_svrSock, 256);
			if(!ec) ec = ec = _service->Init(*dynamic_cast<CSocket*>(_svrSock.Get()), true);
		}
	}
#endif

	return ec;
}

void CIpcServer::AsyncAccept(CIpcSocket& cliSock, const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()){
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}
	cliSock.SetAddr(_svrSock->GetAddr().c_str());
	cliSock.SetDomain(_svrSock->GetDomain());
	cliSock.SetProtocol(_svrSock->GetProtocol());
	cliSock.SetSockType(_svrSock->GetSockType());
	_service->PostAcceptEx(*dynamic_cast<CSocket*>(_svrSock.Get()), cliSock, func, invoker);
}

void CIpcServer::AsyncRead(CIpcSocket& sock, const CStreamIteator& buff, const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()){
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	_service->DeliveryRecv(*dynamic_cast<CSocket*>(&sock), const_cast<char*>(buff.cbegin()), const_cast<char*>(buff.cend()), NullPtr, func, invoker);
}

void CIpcServer::AsyncSend(CIpcSocket& sock, const CStreamIteator& buff, const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()){
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	_service->DeliveryWrite(*dynamic_cast<CSocket*>(&sock), const_cast<char*>(buff.cbegin()), const_cast<char*>(buff.cend()), NullPtr, func, invoker);
}

void CIpcServer::Post(const SharedPtr<HandleBase>& func, void* invoker /* = NullPtr */)
{
	if (!_service->IsInit()){
		throw CSockException(CSockError(CSockError::UNINIT).GetErrorMsg().c_str());
	}

	_service->Post(func, invoker);
}

bool CIpcServer::Run_One()
{
	return _service->Run_One();
}

bool CIpcServer::Run()
{
	return _service->Run();
}

void CIpcServer::NotifyStop()
{
	return _service->NotifyStop();
}

void CIpcServer::WaitServerStop()
{
	_service->NotifyStop();
	_service->Shutdown();
}

bool CIpcServer::IsStop() const
{
	return _service->IsStop();
}

CIoPortService* CIpcServer::GetIoPortService()
{
	return dynamic_cast<CIoPortService*>(_service.Get());
}

void CIpcServer::DelTimer(CTimerBase& timer)
{
	_service->DelTimer(*timer.GetTimerInfo());
}

void CIpcServer::SetTimer(CTimerBase& timer)
{
	_service->SetTimer(*timer.GetTimerInfo());
}

bool CIpcServer::UpdateTimer(CTimerBase& timer)
{
	return _service->UpdateTimer(*timer.GetTimerInfo());
}

DWORD CIpcServer::IoCompleteFunc(OVERLAPPED_EX* o)
{
	DWORD dwRet = 0;
	SharedPtr<HandleBase> handle;
	handle.Swap(o->handle);
	if (o->sockStatus == SOCKETSTATUS::ACCEPTED)
	{
		dwRet = (*handle)(o->sockError, o->invoker);
	}
	else if (o->sockStatus == SOCKETSTATUS::RECVED)
	{
		dwRet = (*handle)(o->wsaPtr.buf, o->dwRead, o->sockError, o->invoker);
	}
	else if (o->sockStatus == SOCKETSTATUS::SENDED)
	{
		dwRet = (*handle)(o->wsaPtr.buf, o->dwWrite, o->sockError, o->invoker);
	}
	else if (o->sockStatus == SOCKETSTATUS::POST)
	{
		dwRet = (*handle)(o->invoker);
	}
	else
	{
		assert(dwRet);
	}

	return dwRet;
}

DEF_END_LIBTOOLS